package ControlComponents;

import DataFormatConversionComponents.NumberConverter;
import Exceptions.InvalidArrayLengthException;

/**
 * 
 *  This class represents a 16 bit instruction register
 *
 */
public class InstructionRegister {

	private int[] ir;
	
	/**
	 * Initialize the instruction register reference
	 */
	public InstructionRegister(){
		
		ir = new int[16];
	}
	
	/**
	 * Return the instruction register 
	 * @return instruction register
	 */
	public int[] get(){
		return ir;
	}
	
	/**
	 * Reset the data at the instruction register
	 * @param data - the data to be stored
	 * @throws InvalidArrayLengthException - if length exceed 8 bits
	 */
	public void set(int[] data)throws InvalidArrayLengthException{
		if( data.length != 16 )
			throw new InvalidArrayLengthException("Cannot set program counter. Expected data.length = 16. Received +" +
					"data.length = " + data.length );
		//copy data to instruction register
		for( int i = 0; i < data.length; i++ )
			ir[i] = data[i];
	}
	
	/**
	 * This method extracts an instruction's opcode. This opcode is actually the first 
	 * 5 elements from private instance array "ir"
	 * @return an integer array with 5 elements; each element corresponds to each opcode bit
	 */
	public int getOpcode(){
		int[] opcode = new int[5];
		for(int i = 0; i < opcode.length; i++ ){
			opcode[i] = ir[i];
		}
		
		
		return new NumberConverter().binaryToDecimal(opcode);
	}
	
	/**
	 * This method extracts 3 bits that correspond to a register's index (0-7) from a 16-bit instruction
	 * @return an integer that identifies which register is to be used (3-bits converted to decimal value)
	 */
	public int getRf(){
		int[] regId = new int[3];
		regId[0] = ir[5];
		regId[1] = ir[6];
		regId[2] = ir[7];

		 int result = new NumberConverter().binaryToDecimal(regId);

		return result;
	}

	/**
	 * This method extracts the last 8 bits from a given instruction. These bits correspond to a direct address when
	 * using the direct addressing mode
	 * @return an integer equivalent of the 8 bit address extracted from the given extraction
	 */
	public int getDirectAddress(){
		int[] directAddress = new int[8];
		for(int i = 8, j = 0; i <= 15; i++, j++ )
			directAddress[j] = ir[i];
		return new NumberConverter().binaryToDecimal( directAddress );
	}


	/**
	 * This operation is used to extract an immediate operand from an instruction (last 8 bits)
	 * @return an integer array that contains the instructions immediate operand
	 */
	public int[] getImmediateOperand() {
		int[] immediateAddress = new int[8];
		for(int i = 8, j = 0; i <=15 ; i++, j++ )
			immediateAddress[j] = ir[i];
		return immediateAddress;
	}
}
